package xyz.cerberu.cet.user.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import io.minio.MinioClient;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import xyz.cerberu.cet.global.domain.FileHeaderType;
import xyz.cerberu.cet.global.utils.AESUtils;
import xyz.cerberu.cet.global.utils.FileUtils;
import xyz.cerberu.cet.user.domain.MinIo;
import xyz.cerberu.cet.user.domain.PictureDTO;
import xyz.cerberu.cet.user.exception.FileTypeNotConformException;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.time.ZoneOffset;

/**
 * @author β世界
 * Created on 12:54
 * @Description 用户头像服务,服务基于MinIo实现
 *
 * 可能遇见问题：
 *      非法路径读取问题
 *          例：文件名为"../../Test.png",系统可能会识别为往上读取两个文件夹去找这个文件，可能会被特殊执行
 */
public class MinIoPictureServiceImpl implements PictureService{
    /** minio配置对象 **/
    private final MinIo minIo;
    /** minio的客户端 **/
    private final MinioClient minioClient;
    /** AES加密的密钥 **/
    private final static String AES_KEY = "NWSZLGSCQWUYSGQS";
    private final static String PICTURE_ORIGINAL_NAME = "pictureOriginalName";
    private final static String LAST_UPLOAD = "lastUpload";

    @Autowired
    public MinIoPictureServiceImpl(MinioClient minioClient,MinIo minIo) {
        this.minioClient = minioClient;
        this.minIo = minIo;
    }

    /**
     * @author β世界 on 21:47 2021/3/29
     * 将文件对象存储于MinIo中，为了防止用户断时间上传多次，我们需要记录下最后的上传时间
     * 对象进行存储的时候，存储的就是源文件名，但是向上返回一个经过加密的字符串
     * 返回一个有效的存储对象URl
     * @param inputStream: 图片的读取流
     * @param pictureDTO: 文件存储名
     * @return java.lang.String
     **/
    @Override
    public String uploadPicture(InputStream inputStream, PictureDTO pictureDTO) throws Exception{
        // 判断桶是否存在
        boolean bucketExist = minioClient.bucketExists(minIo.getPictureBucket());
        if(!bucketExist){
            // 不存在就创建桶
            minioClient.makeBucket(minIo.getPictureBucket());
        }

        // 判断类型是否正确
        byte[] originalData = IOUtils.toByteArray(inputStream);
        if(!FileUtils.checkFileType(originalData, FileHeaderType.GIF,FileHeaderType.JPG,FileHeaderType.PNG)){
            // 抛出文件类型异常的错误
            throw new FileTypeNotConformException("文件类型不正确");
        }
        ByteArrayInputStream byteInputStream = new ByteArrayInputStream(originalData,0,originalData.length);

        // 将对象存储
        minioClient.putObject(minIo.getPictureBucket(), pictureDTO.getFileName(),byteInputStream,pictureDTO.getFileType());
        // 对内容进行存储
        JSONObject jsonObject = new JSONObject();
        jsonObject.put(PICTURE_ORIGINAL_NAME, pictureDTO.getFileName());
        jsonObject.put(LAST_UPLOAD, LocalDateTime.now().atOffset(ZoneOffset.of("+8")).toEpochSecond());
        // 返回一个经过加密的pictureId
        IOUtils.closeQuietly(byteInputStream);
        return AESUtils.encode(jsonObject.toString(),AES_KEY);
    }

    /**
     * @author β世界 on 22:30 2021/3/29
     * 根据传递过来的对象存储名来获取
     * @param pictureId: 业务对象
     * @return java.io.InputStream
     **/
    @Override
    public InputStream getPicture(String pictureId) throws Exception {
        JSONObject jsonObject = JSON.parseObject(AESUtils.decode(pictureId, AES_KEY));
        // 获取图片
        return minioClient.getObject(minIo.getPictureBucket(),(String) jsonObject.get(PICTURE_ORIGINAL_NAME));
    }
}
